﻿using System;
using System.Security.Cryptography;
using System.Text;

namespace HuaXingSDK
{
    internal static class Uilts
    {
        private const string keys = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        private static int exponent = keys.Length;

        public static string Decimal2Str(decimal value)
        {
            var result = string.Empty;
            do
            {
                var index = value % exponent;
                result = keys[(int)index] + result;
                value = (value - index) / exponent;
            }
            while (value > 0);

            return result;
        }

        public static decimal Str2Decimal(string value)
        {
            decimal result = 0;
            for (var i = 0; i < value.Length; i++)
            {
                var x = value.Length - i - 1;
                result += keys.IndexOf(value[i]) * Pow(exponent, x);
            }
            return result;
        }

        private static decimal Pow(decimal baseNo, decimal x)
        {
            decimal value = 1;
            while (x > 0)
            {
                value = value * baseNo;
                x--;
            }
            return value;
        }

        public static string MD5(string data, Encoding encoding = null, bool len16 = false)
        {
            encoding = encoding ?? Encoding.ASCII;
            using (var md5 = new MD5CryptoServiceProvider())
            {
                var source = md5.ComputeHash(encoding.GetBytes(data));
                if (len16)
                {
                    return BitConverter.ToString(source, 4, 8).Replace("-", "");
                }
                var sb = new StringBuilder();
                foreach (var t in source)
                {
                    sb.Append(t.ToString("x2"));
                }
                return sb.ToString();
            }
        }

        public static string Encrypt3DES(string key, string content, Encoding encoding = null)
        {
            if (string.IsNullOrEmpty(content))
                throw new ArgumentNullException(nameof(content));
            encoding = encoding ?? Encoding.UTF8;
            var des = new TripleDESCryptoServiceProvider
            {
                Key = encoding.GetBytes(key),
                Mode = CipherMode.ECB
            };
            var enc = des.CreateEncryptor();
            var data = encoding.GetBytes(content);
            return Convert.ToBase64String(enc.TransformFinalBlock(data, 0, data.Length));
        }

        public static string Decrypt3DES(string key, string content, Encoding encoding = null)
        {
            if (string.IsNullOrEmpty(content))
                throw new ArgumentNullException(nameof(content));
            encoding = encoding ?? Encoding.UTF8;
            var des = new TripleDESCryptoServiceProvider
            {
                Key = Encoding.ASCII.GetBytes(key),
                Mode = CipherMode.ECB,
                Padding = PaddingMode.PKCS7
            };
            var decr = des.CreateDecryptor();
            var data = Convert.FromBase64String(content);
            return encoding.GetString(decr.TransformFinalBlock(data, 0, data.Length));
        }

        public static string GetId(int length)
        {
            var str = string.Empty;

            do
            {
                var num = Guid.NewGuid().GetHashCode();
                if (num < 0)
                {
                    num *= -1;
                }
                str += Decimal2Str(num);
            } while (str.Length < length);

            return str.Substring(0, length);
        }

        public static bool CheckSign(string message, out string xml)
        {
            var prelen = HXConfigs.MsgHeadLength;
            var seclen = HXConfigs.MsgSecLength;
            var str = message.Substring(prelen, seclen).TrimStart('0');
            int len;
            if (!int.TryParse(str, out len) || message.Length < prelen + seclen + len)
                throw new HXException("报文格式不正确。");
            var decr = message.Substring(prelen + seclen, len);
            var text = message.Substring(prelen + seclen + len);
            var sign = GetSign(text);
            xml = text;
            if (sign.Equals(decr, StringComparison.OrdinalIgnoreCase))
            {
                xml = text;
                return true;
            }
            return false;
        }

        public static string GetSign(string outerXml)
        {
            var md5 = MD5(outerXml).ToUpper();
            var data = RSAForJava.EncryptByPrivateKey(md5, HXConfigs.RSAPrivateKey);
            return BitConverter.ToString(data).Replace("-", "").ToUpper();
        }

        public static string DecryptXmlPara(string outerXml)
        {
            return Decrypt3DES(HXConfigs.TripleDESKey, outerXml);
        }
    }
}
